package com.cxx.purchasecharge.component.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.bean.GenericPagingResult;
import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.OrderBean;
import com.cxx.purchasecharge.component.bean.OrderItemBean;
import com.cxx.purchasecharge.component.bean.OrderPrinter;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.bean.SearchRequestForm;
import com.cxx.purchasecharge.component.exception.ApplicationException;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.config.FileSystemUtil;
import com.cxx.purchasecharge.core.model.OrderSearchForm;
import com.cxx.purchasecharge.core.model.OrderStatusCode;
import com.cxx.purchasecharge.core.model.OrderTypeCode;
import com.cxx.purchasecharge.core.model.persistence.Order;
import com.cxx.purchasecharge.core.model.persistence.OrderItem;
import com.cxx.purchasecharge.core.model.persistence.Payment;
import com.cxx.purchasecharge.core.model.persistence.User;
import com.cxx.purchasecharge.core.util.DateUtils;
import com.cxx.purchasecharge.dal.DaoContext;
import com.cxx.purchasecharge.dal.common.IDGenerator;
import com.cxx.purchasecharge.service.CoreService;
import com.cxx.purchasecharge.service.QueryService;

@Controller
@RequestMapping ("/outOrder")
public class OutOrderManager extends GenericController <OrderBean>
{
    private static final Logger logger = Logger.getLogger (OutOrderManager.class);

    @Autowired
    private CoreService coreService;
    @Autowired
    private QueryService queryService;
    @Autowired
    private PCApplicationContext pcContext;
    
    //public static final List<String> staticOrderColumnHeaders;
    public static final String[] staticOrderColumnHeaders = {"goodsId", "goodsName", "goodsUnit", "goodsPrice", "goodsAmount", "goodsMoney", "comment"};

    public OutOrderManager ()
    {
        super.setViewName("outOrderManagement");
    }
    
    @RequestMapping (value = "/outOrderProfitView")
    public String redirectToOrderProfitView (ModelMap model)
    {
        return "outOrderProfitView";
    }

    @Override
    public String getModelBySearchForm(
        DataGridRequestForm dataGridRequestForm,
        SearchRequestForm searchRequestForm,
        HttpServletRequest request)
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = parseSortField (dataGridRequestForm.getSort ());
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        LoginUser loginUser = null;
        String type = "";
        try
        {
            loginUser = pcContext.getLoginUser (request);
            type = validateOrderType (request);
        }
        catch (Exception e)
        {
            logger.warn(e.getMessage(), e);
        }
        
        if (null != loginUser)
        {
            OrderTypeCode typeCode = OrderTypeCode.OUT.toString ().equals (type) ? OrderTypeCode.OUT
                                                                                : OrderTypeCode.OUT_RETURN;
            OrderSearchForm searchForm = BeanConvertUtils.searchRequestForm2OrderSearchForm (searchRequestForm);
            Page <Order> orderPage = null;
            List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
            if (null != searchForm && searchForm.getOrderId () != 0)
            {
                Order ord = queryService.findOrderById (searchForm.getOrderId ());
                List <Order> list = new ArrayList <Order> ();
                orderPage = new PageImpl <Order> (list, pageable, 0);
                if (null != ord)
                {
                    list.add (ord);
                    orderPage = new PageImpl <Order> (list, pageable, 1);
                }
                footer = countTotalForOrders (orderPage.getContent ());
            }
            else
            {
                orderPage = queryService.findOrderBySearchForm (typeCode, pageable, searchForm, loginUser.getUserId (),
                                                                loginUser.isAdmin ());
                float sumReceivable = queryService.countOrderReceivableBySearchForm (typeCode, searchForm, loginUser.getUserId (),
                                                                loginUser.isAdmin ());
                float sumProfit = queryService.countOrderProfitBySearchForm (typeCode, searchForm, loginUser.getUserId (),
                                                                loginUser.isAdmin ());
                Map <String, String> map = new HashMap <String, String> ();
                map.put ("id", "合计");
                map.put (ComponentConstants.RECEIVABLE_MONEY, sumReceivable + "");
                map.put (ComponentConstants.PROFIT_MONEY, sumProfit + "");
                footer.add (map);
            }

            long total = orderPage.getTotalElements ();
            GenericPagingResult <OrderBean> orderPagingResult = new GenericPagingResult <OrderBean> ();
            orderPagingResult.setRows (BeanConvertUtils.orderList2OrderBeanList (orderPage.getContent ()));
            orderPagingResult.setTotal (total);
            orderPagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
            return jsonObject.toString ();
        }
        return "";
    }

    @Override
    public String getModelById(@RequestParam String orderId, HttpServletRequest request)
    {
        if (StringUtils.isNotBlank (orderId))
        {
            Order order = new Order ();
            order.setId (Long.parseLong (orderId));
            List <OrderItem> orderItems = queryService.findOrderItemByOrder (order);
            if (!CollectionUtils.isEmpty (orderItems))
            {
                // JSONArray jsonArray = JSONArray.fromObject
                // (BeanConvertUtils.orderItemList2OrderItemBeanList
                // (orderItems));
                // return jsonArray.toString ();
                GenericPagingResult <OrderItemBean> orderPagingResult = new GenericPagingResult <OrderItemBean> ();
                orderPagingResult.setRows (BeanConvertUtils.orderItemList2OrderItemBeanList (orderItems));
                orderPagingResult.setTotal (orderItems.size ());
                orderPagingResult.setFooter (countTotalForOrderItems (orderItems));

                JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
                return jsonObject.toString ();
            }
        }
        return "";
    }

    @RequestMapping (value = "/getOrderItemTable", method = RequestMethod.POST)
    public void getOrderItemTable(@RequestParam String orderId, @RequestParam String templateFile, HttpServletResponse response) throws Exception
    {
        response.setContentType ("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter ();
        StringBuffer html = new StringBuffer ("");
        
        String orderTemplate = FileSystemUtil.readFileToString(templateFile);
        List<String> configuredColumnHeaders = getOrderColumnHeaderTemplate(orderTemplate);
        if(CollectionUtils.isEmpty(configuredColumnHeaders)) 
        {
            html.append("No order header found");
            writer.print (html.toString ());
        }
        else 
        {
            // validate
            List<String> availableColumnHeaders = new ArrayList<String>();
            for(String orderColumnHeader : staticOrderColumnHeaders) 
            {
                if(configuredColumnHeaders.contains(orderColumnHeader)) 
                {
                    availableColumnHeaders.add(orderColumnHeader);
                }
            }
            if(availableColumnHeaders.isEmpty()) 
            {
                html.append("No correct order header found, expected headers are " + staticOrderColumnHeaders);
                writer.print (html.toString ());
            }
            
            if (StringUtils.isNotBlank (orderId))
            {
                Order order = new Order ();
                order.setId (Long.parseLong (orderId));
                List <OrderItem> orderItems = queryService.findOrderItemByOrder (order);
                if (!CollectionUtils.isEmpty (orderItems))
                {
                    String trs = "";
                    for (OrderItem orderItem : orderItems)
                    {
                        String tr = "";
                        tr += "<tr>";
                        for(String columnHeader : availableColumnHeaders) 
                        {
                            if(staticOrderColumnHeaders[0].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getGoods ().getId () + "</td>";
                            }
                            else if(staticOrderColumnHeaders[1].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getGoods ().getName () + "</td>";
                            }
                            else if(staticOrderColumnHeaders[2].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getGoods ().getUnit ().getName () + "</td>";
                            }
                            else if(staticOrderColumnHeaders[3].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getUnitPrice() + "</td>";
                            }
                            else if(staticOrderColumnHeaders[4].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getAmount () + "</td>";
                            }
                            else if(staticOrderColumnHeaders[5].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getSum() + "</td>";
                            }
                            else if(staticOrderColumnHeaders[6].equalsIgnoreCase(columnHeader)) 
                            {
                                tr += "<td>" + orderItem.getComment() + "</td>";
                            }
                        }
                        tr += "</tr>";
                        trs += tr;
                    }
                    
                    orderTemplate = orderTemplate.replace("{:orderContent}", trs);
                    List<Map<String, String>> orderItemCount = countTotalForOrderItems(orderItems);
                    orderTemplate = orderTemplate.replace("{:amountSum}", orderItemCount.get(0).get(ComponentConstants.ORDER_AMOUNT));
                    orderTemplate = orderTemplate.replace("{:moneySum}", orderItemCount.get(0).get(ComponentConstants.ORDER_SUM));
                }
                writer.print (html.append(orderTemplate).toString ());
            }
        }
    }
    
    private List<String> getOrderColumnHeaderTemplate(String templateStr) throws IOException 
    {
        Pattern pattern = Pattern.compile("<th id=\".*@\""); 
        Matcher matcher = pattern.matcher(templateStr); 
        List<String> configuredColumnHeaders = new ArrayList<String>();
        while (matcher.find()) { 
            String th = matcher.group();
            Pattern pattern2 = Pattern.compile("\".*@"); 
            Matcher matcher2 = pattern2.matcher(th);
            while(matcher2.find()) 
            {
                String ths = matcher2.group();
                configuredColumnHeaders.add(ths.substring(1, ths.lastIndexOf("@")));
            }
        }
        return configuredColumnHeaders;
    }
    
    @RequestMapping (value = "/printOrder", method = RequestMethod.POST)
    public void printOrder(OrderPrinter orderPrinter, HttpServletResponse response) throws Exception
    {
        response.setContentType ("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter ();
        
        String orderPrintTemplate = FileSystemUtil.readFileToString(orderPrinter.getTemplate());
        List<String> configuredColumnHeaders = getOrderColumnHeaderTemplate(orderPrintTemplate);
        StringBuffer html = new StringBuffer ("");
        if(CollectionUtils.isEmpty(configuredColumnHeaders)) 
        {
            html.append("No order header found");
            writer.print (html.toString ());
        }
        else 
        {
            // validate
            List<String> availableColumnHeaders = new ArrayList<String>();
            for(String orderColumnHeader : staticOrderColumnHeaders) 
            {
                if(configuredColumnHeaders.contains(orderColumnHeader)) 
                {
                    availableColumnHeaders.add(orderColumnHeader);
                }
            }
            if(availableColumnHeaders.isEmpty()) 
            {
                html.append("No correct order header found, expected headers are " + staticOrderColumnHeaders);
                writer.print (html.toString ());
            }
            
            if (null != orderPrinter && StringUtils.isNotBlank (orderPrinter.getOrderId()))
            {
                Order order = queryService.findOrderById(Long.parseLong (orderPrinter.getOrderId()));
                if(null != order) 
                {
                    List <OrderItem> orderItems = queryService.findOrderItemByOrder(order);
                    if (!CollectionUtils.isEmpty (orderItems))
                    {
                        String trs = "";
                        for (OrderItem orderItem : orderItems)
                        {
                            String tr = "";
                            tr += "<tr>";
                            for(String columnHeader : availableColumnHeaders) 
                            {
                                if(staticOrderColumnHeaders[0].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getGoods ().getId () + "</td>";
                                }
                                else if(staticOrderColumnHeaders[1].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getGoods ().getName () + "</td>";
                                }
                                else if(staticOrderColumnHeaders[2].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getGoods ().getUnit ().getName () + "</td>";
                                }
                                else if(staticOrderColumnHeaders[3].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getUnitPrice() + "</td>";
                                }
                                else if(staticOrderColumnHeaders[4].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getAmount () + "</td>";
                                }
                                else if(staticOrderColumnHeaders[5].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getSum() + "</td>";
                                }
                                else if(staticOrderColumnHeaders[6].equalsIgnoreCase(columnHeader)) 
                                {
                                    tr += "<td>" + orderItem.getComment() + "</td>";
                                }
                            }
                            tr += "</tr>";
                            trs += tr;
                        }
                        
                        orderPrintTemplate = orderPrintTemplate.replace("{:title}", orderPrinter.getTitle());
                        orderPrintTemplate = orderPrintTemplate.replace("{:orderId}", order.getId() + "");
                        orderPrintTemplate = orderPrintTemplate.replace("{:printDate}", DateUtils.date2String(new Date(), DateUtils.DATE_TIME_PATTERN));
                        orderPrintTemplate = orderPrintTemplate.replace("{:orderDate}", DateUtils.date2String(order.getCreateDate(), DateUtils.DATE_PATTERN));
                        orderPrintTemplate = orderPrintTemplate.replace("{:customerName}", order.getCustomer().getShortName());
                        orderPrintTemplate = orderPrintTemplate.replace("{:contactName}", orderPrinter.getContactName());
                        orderPrintTemplate = orderPrintTemplate.replace("{:contactPhone}", orderPrinter.getContactPhone());
                        orderPrintTemplate = orderPrintTemplate.replace("{:contactAddress}", orderPrinter.getContactAddress());
                        orderPrintTemplate = orderPrintTemplate.replace("{:orderContent}", trs);
                        List<Map<String, String>> orderItemCount = countTotalForOrderItems(orderItems);
                        orderPrintTemplate = orderPrintTemplate.replace("{:amountSum}", orderItemCount.get(0).get(ComponentConstants.ORDER_AMOUNT));
                        orderPrintTemplate = orderPrintTemplate.replace("{:moneySum}", orderItemCount.get(0).get(ComponentConstants.ORDER_SUM));
                        User user = DaoContext.getUserDao().findOne(order.getUserOperatedBy());
                        if(null != user) 
                        {
                            orderPrintTemplate = orderPrintTemplate.replace("{:operator}", user.getUserId());
                        }
                        user = DaoContext.getUserDao().findOne(order.getCustomer().getUserSigned());
                        if(null != user) 
                        {
                            orderPrintTemplate = orderPrintTemplate.replace("{:salesman}", user.getUserId());
                        }
                        orderPrintTemplate = orderPrintTemplate.replace("{:footer}", orderPrinter.getFooter());
                        writer.print (html.append(orderPrintTemplate).toString ());
                    }
                }
            }
        }
    }

    @Override
    public String addModel(@Valid OrderBean bean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                bean.setOrderItemBeans (parseOrderItem (bean));
                Order order = BeanConvertUtils.orderBean2Order (bean);
                order.setId (IDGenerator.getIdentityID ());
                coreService.saveOrder (order);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
    }

    @Override
    public String updateModel(OrderBean bean, BindingResult bindingResult, HttpServletRequest request)
    {
        if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                coreService.updateOrderStatus (Long.parseLong (bean.getId ()), bean.getStatusCode (),
                                               bean.getComment ());
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_OUT_ORDER_STATUS))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                                                                                     ComponentConstants.MSG_OUT_ORDER_STATUS))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
        
        /*if (bindingResult.hasErrors ())
        {
            logger.error (bindingResult.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                Order order = BeanConvertUtils.orderBean2Order (bean);
                coreService.saveOrder (order);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_FAIL,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }*/
    }

    @Override
    public String deleteModels(@RequestParam String ids, HttpServletRequest request)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <Order> orders = new ArrayList <Order> ();
            Order order;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    order = new Order ();
                    order.setId (Long.parseLong (typeId));
                    orders.add (order);
                }
            }
            else
            {
                order = new Order ();
                order.setId (Long.parseLong (ids));
                orders.add (order);
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                coreService.deleteOrders (orders);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_FAIL,
                                                                                     ComponentConstants.MSG_OUT_ORDER))
                                 .build ();
            }
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST);
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }
    
    @RequestMapping (value = "/getOrderItemsByOrderIds", method = RequestMethod.POST)
    public @ResponseBody
    String getOrderItemsByOrderIds (@RequestParam String orderIds)
    {
        if (StringUtils.isNotBlank (orderIds))
        {
            List <OrderItem> orderItems = new ArrayList <OrderItem> ();
            if (orderIds.indexOf (";") != -1)
            {
                String[] idArr = orderIds.split (";");
                for (String orderId : idArr)
                {
                    long oId = Long.parseLong (orderId);
                    orderItems.addAll (queryService.findOrderItemWithOrder (oId));
                }
            }
            else
            {
                long oId = Long.parseLong (orderIds);
                orderItems.addAll (queryService.findOrderItemWithOrder (oId));
            }
            
            if (!CollectionUtils.isEmpty (orderItems))
            {
                GenericPagingResult <OrderItemBean> orderPagingResult = new GenericPagingResult <OrderItemBean> ();
                orderPagingResult.setRows (BeanConvertUtils.orderItemList2OrderItemBeanList (orderItems));
                orderPagingResult.setTotal (orderItems.size ());
                orderPagingResult.setFooter (countTotalForOrderItems (orderItems));
                
                JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
                return jsonObject.toString ();
            }
        }
        return "";
    }
    
    @RequestMapping (value = "/getLatestGoodsUnitPrice", method = RequestMethod.POST)
    public @ResponseBody
    String getLatestGoodsUnitPrice (@RequestParam String customerId, @RequestParam String goodsId)
    {
        String result = "";
        List <OrderItemBean> orderItemList = new ArrayList <OrderItemBean> ();
        if (StringUtils.isNotBlank (customerId) && StringUtils.isNotBlank (goodsId))
        {
            long goodsUid = Long.parseLong (goodsId);
            List <Order> orderList = queryService.getOrderByCustomer (Long.parseLong (customerId));
            if (!CollectionUtils.isEmpty (orderList))
            {
                for (Order order : orderList)
                {
                    List <OrderItem> orderItems = queryService.getOrderItemByOrder (order);
                    if (!CollectionUtils.isEmpty (orderItems))
                    {
                        for (OrderItem orderItem : orderItems)
                        {
                            if (goodsUid == orderItem.getGoods ().getId ())
                            {
                                OrderItemBean orderItemBean = BeanConvertUtils.orderItem2OrderItemBean (orderItem);
                                orderItemBean.setOrderCreate (DateUtils.date2String (order.getCreateDate (),
                                                                                     DateUtils.DATE_TIME_PATTERN));
                                orderItemList.add (orderItemBean);
                            }
                        }
                    }
                }
            }
        }

        OrderItemBean latestItem = getLatestOrderItem (orderItemList);
        if (null != latestItem)
        {
            result = JSONObject.fromObject (latestItem).toString ();
        }
        return result;
    }
    
    @RequestMapping (value = "/getOrderProfit", method = RequestMethod.POST)
    public @ResponseBody
    String getOrderProfit (DataGridRequestForm dataGridRequestForm, SearchRequestForm searchRequestForm,
                                 HttpServletRequest request) throws Exception
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = (null == dataGridRequestForm.getSort ()) ? "customer.shortName"
                                                                   : ComponentConstants.CREATE_DATE;
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        boolean isOut = true;
        LoginUser loginUser = pcContext.getLoginUser (request);
        if (null != loginUser)
        {
            OrderSearchForm searchForm = BeanConvertUtils.searchRequestForm2OrderSearchForm (searchRequestForm);
            List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
            Page <Order> orderPage = queryService.findOrderBySearchForm (isOut, pageable, searchForm,
                                                                         loginUser.getUserId (), loginUser.isAdmin ());

            float sumReceivable = queryService.countOrderReceivableBySearchForm (OrderTypeCode.OUT, searchForm,
                                                                                 loginUser.getUserId (),
                                                                                 loginUser.isAdmin ());
            float sumUnReceivable = queryService.countOrderReceivableBySearchForm (OrderTypeCode.OUT_RETURN,
                                                                                   searchForm, loginUser.getUserId (),
                                                                                   loginUser.isAdmin ());
            float sumProfit = queryService.countOrderProfitBySearchForm (OrderTypeCode.OUT, searchForm,
                                                                         loginUser.getUserId (), loginUser.isAdmin ());
            float sumUnProfit = queryService.countOrderProfitBySearchForm (OrderTypeCode.OUT_RETURN, searchForm,
                                                                           loginUser.getUserId (), loginUser.isAdmin ());

            Map <String, String> map = new HashMap <String, String> ();
            map.put ("id", "合计");
            map.put (ComponentConstants.RECEIVABLE_MONEY, sumReceivable - sumUnReceivable + "");
            map.put (ComponentConstants.PROFIT_MONEY, sumProfit - sumUnProfit + "");
            footer.add (map);

            long total = orderPage.getTotalElements ();
            GenericPagingResult <OrderBean> orderPagingResult = new GenericPagingResult <OrderBean> ();
            orderPagingResult.setRows (BeanConvertUtils.orderList2OrderBeanList (orderPage.getContent ()));
            orderPagingResult.setTotal (total);
            orderPagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (orderPagingResult);
            return jsonObject.toString ();
        }
        else
        {
            throw new ApplicationException ();
        }
    }

    private String validateOrderType (HttpServletRequest request) throws ApplicationException
    {
        String type = request.getParameter ("type");
        if (StringUtils.isBlank (type))
        {
            throw new ApplicationException ("Order type code is empty.");
        }
        if (!OrderTypeCode.OUT.toString ().equals (type) && !OrderTypeCode.OUT_RETURN.toString ().equals (type))
        {
            throw new ApplicationException (
                                            "Order type code '"
                                                    + type
                                                    + "' is not supported, accepted type code is OrderTypeCode.OUT or OrderTypeCode.OUT_RETURN.");
        }
        return type;
    }

    private List <Map <String, String>> countTotalForOrderItems (List <OrderItem> orderItemList)
    {
        List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
        if (!CollectionUtils.isEmpty (orderItemList))
        {
            Map <String, String> map = new HashMap <String, String> ();
            int amountTotal = 0;
            float sumTotal = 0;
            for (OrderItem ordItem : orderItemList)
            {
                amountTotal += ordItem.getAmount ();
                sumTotal += ordItem.getSum ();
            }
            map.put (ComponentConstants.ORDER_UNIT_PRICE, "合计");
            map.put (ComponentConstants.ORDER_AMOUNT, amountTotal + "");
            map.put (ComponentConstants.ORDER_SUM, sumTotal + "");
            footer.add (map);
        }
        return footer;
    }

    @SuppressWarnings ("unused")
    private List <Map <String, Object>> countOrderPaid (float dealMoney, List <Payment> payments)
    {
        List <Map <String, Object>> footer = new ArrayList <Map <String, Object>> ();
        if (!CollectionUtils.isEmpty (payments))
        {
            Map <String, Object> map = new HashMap <String, Object> ();
            float countOrderPaid = 0;
            String paidResult = "";
            for (Payment op : payments)
            {
                countOrderPaid += op.getPaid ();
            }
            if (dealMoney == countOrderPaid)
            {
                paidResult = "回款完成";
            }
            else if (dealMoney > countOrderPaid)
            {
                paidResult = "欠" + (dealMoney - countOrderPaid);
            }
            map.put (ComponentConstants.PAY_DATE, "状态");
            map.put (ComponentConstants.PAID, paidResult);
            footer.add (map);
        }
        else
        {
            Map <String, Object> map = new HashMap <String, Object> ();
            map.put (ComponentConstants.PAY_DATE, "状态");
            map.put (ComponentConstants.PAID, "尚无回款");
            footer.add (map);
        }
        return footer;
    }

    private List <Map <String, String>> countTotalForOrders (List <Order> orderList)
    {
        List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
        if (!CollectionUtils.isEmpty (orderList))
        {
            Map <String, String> map = new HashMap <String, String> ();
            float dealMoneyTotal = 0;
            // float paidMoneyTotal = 0;
            float receivableMoneyTotal = 0;
            float profitMoneyTotal = 0;
            for (Order ord : orderList)
            {
                if (ord.getStatusCode () == OrderStatusCode.FINISHED || ord.getStatusCode () == OrderStatusCode.NEW)
                {
                    dealMoneyTotal += ord.getDealMoney ();
                    receivableMoneyTotal += ord.getReceivable ();
                    // paidMoneyTotal += ord.getPaidMoney ();
                    profitMoneyTotal += ord.getProfit ();
                }
            }
            // map.put (ComponentConstants.CUSTOMER_NAME, "当页合计");
            map.put ("id", "合计");
            map.put (ComponentConstants.DEAL_MONEY, dealMoneyTotal + "");
            map.put (ComponentConstants.RECEIVABLE_MONEY, receivableMoneyTotal + "");
            // map.put (ComponentConstants.PAID_MONEY, paidMoneyTotal + "");
            map.put (ComponentConstants.PROFIT_MONEY, profitMoneyTotal + "");
            footer.add (map);
        }
        return footer;
    }

    private String parseSortField (final String sortField)
    {
        String sortFieldAfterParse = ComponentConstants.CUSTOMER_DOT_SHORT_NAME;
        if (!StringUtils.isBlank (sortField))
        {
            sortFieldAfterParse = sortField;
            if (ComponentConstants.CUSTOMER_NAME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.CUSTOMER_DOT_SHORT_NAME;
            }
            else if (ComponentConstants.PAY_TIME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.PAY_DATE;
            }
            else if (ComponentConstants.CREATE_TIME.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.CREATE_DATE;
            }
        }
        return sortFieldAfterParse;
    }

    private List <OrderItemBean> parseOrderItem (OrderBean orderBean)
    {
        List <OrderItemBean> orderItemBeans = new ArrayList <OrderItemBean> ();
        String orderItemListStr = orderBean.getOrderItemList ();
        try
        {
            if (StringUtils.isNotBlank (orderItemListStr))
            {
                String[] orderItemArr = orderItemListStr.split (";");
                if (orderItemArr.length > 0)
                {
                    for (String orderItem : orderItemArr)
                    {
                        if (StringUtils.isNotBlank (orderItem))
                        {
                            String[] itemArr = orderItem.split (",");
                            OrderItemBean orderItemBean = new OrderItemBean ();
                            orderItemBean.setId (itemArr[0]);
                            orderItemBean.setGoodsId (itemArr[1]);
                            orderItemBean.setGoodsUnit (itemArr[2]);
                            orderItemBean.setUnitPrice (StringUtils.isNotBlank (itemArr[3]) ? Float.parseFloat (itemArr[3])
                                                                                           : 0);
                            orderItemBean.setAmount (StringUtils.isNotBlank (itemArr[4]) ? Integer.parseInt (itemArr[4])
                                                                                        : 0);
                            orderItemBean.setSum (StringUtils.isNotBlank (itemArr[6]) ? Float.parseFloat (itemArr[6])
                                                                                     : 0);
                            orderItemBean.setComment (itemArr[5]);
                            orderItemBean.setImportPrice (StringUtils.isNotBlank (itemArr[7]) ? Float.parseFloat (itemArr[7])
                                                                                             : 0);
                            orderItemBeans.add (orderItemBean);
                        }
                    }
                }
            }
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
            logger.warn (e.getMessage () + ". the orderItemListStr: " + orderItemListStr);
        }
        return orderItemBeans;
    }

    private OrderItemBean getLatestOrderItem (List <OrderItemBean> orderItemList)
    {
        if (!CollectionUtils.isEmpty (orderItemList))
        {
            Collections.sort (orderItemList, new Comparator <OrderItemBean> ()
            {
                @Override
                public int compare (OrderItemBean o1, OrderItemBean o2)
                {
                    return DateUtils.string2Date (o2.getOrderCreate (), DateUtils.DATE_TIME_PATTERN)
                                    .compareTo (DateUtils.string2Date (o1.getOrderCreate (),
                                                                       DateUtils.DATE_TIME_PATTERN));
                }
            });
            return orderItemList.get (0);
        }
        return null;
    }
    
}
